package com.TeamJigsaw.DanteTrail.Presenters;
import java.awt.CardLayout;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JOptionPane;
import javax.swing.ImageIcon;

import com.TeamJigsaw.DanteTrail.Debug.Debug;
import com.TeamJigsaw.DanteTrail.Models.Checkpoint;
import com.TeamJigsaw.DanteTrail.Models.GivingEvent;
import com.TeamJigsaw.DanteTrail.Models.IllnessEvent;
import com.TeamJigsaw.DanteTrail.Models.OxenDeathEvent;
import com.TeamJigsaw.DanteTrail.Models.RecoverIllnessEvent;
import com.TeamJigsaw.DanteTrail.Models.SaveFileHandler;
import com.TeamJigsaw.DanteTrail.Models.SevereStromEvent;
import com.TeamJigsaw.DanteTrail.Models.ThiefEvent;
import com.TeamJigsaw.DanteTrail.Models.TownCheckpoint;
import com.TeamJigsaw.DanteTrail.Models.RiverCheckpoint;
import com.TeamJigsaw.DanteTrail.Models.RandomEvent;
import com.TeamJigsaw.DanteTrail.Models.Party;
import com.TeamJigsaw.DanteTrail.Models.WagonEvent;
import com.TeamJigsaw.DanteTrail.Views.MainViewFrame;
import com.TeamJigsaw.DanteTrail.Views.Interfaces.GameViewInterface;

/**
 * Represents a GameView Controller.
 * @author Vince Lugli
 *
 */

public class GameViewController implements ViewController {

	private Party party;
	
	private List<Checkpoint> checkpoints;
	
	private List<Checkpoint> permMap;
	
	private List<RandomEvent> events;
	
	private MainViewFrame mainView;
	
	private GameViewInterface game;
	
	private Timer timer;
	
	private Checkpoint prevLocation;
	
	private int month, day, year;
	
	private boolean checkMonth;
	
	private RandomEvent thief, illness, wagonEvent, giving, recovered, oxenDeath, severeStorm;
	
	//static constants
	private static final int FIRST_MEMBER = 0;
	
	private static final int SECOND_MEMBER = 1;
	
	private static final int THIRD_MEMBER = 2;
	
	/**
	 * Creates and instantiates a GameView controller with specified model
	 * and view
	 * @param party The party model being used by the game
	 * @param mainView The main UI component
	 */
	public GameViewController (Party party, MainViewFrame mainView){
		this.party = party;
		this.mainView = mainView;
		game = this.mainView.getGameView();
		timer = new Timer();
		month = 1;
		day = 1;
		year = 1830;
		checkMonth = true;
		prevLocation = new TownCheckpoint ("Independence", 0, null,0);
		
		//initialize the checkpoints
		checkpoints = new ArrayList<Checkpoint>();
		permMap = new ArrayList<Checkpoint>();
		initCheckpoints();
		
		//initialize the events
		events = new ArrayList<RandomEvent>();
		initEvents();
		
		//Set the initial values.
		game.setDistanceTravelled(this.party.getTotalDistance());
		game.setRationsLeft(this.party.getFood());
		game.setDistanceToCheckPoint(this.party.getDistanceLeft());
		game.getDisplay().updateScreen(this.party.getPlayer().getStatus(), 
				party.getParty().get(FIRST_MEMBER).getStatus(), 
				party.getParty().get(SECOND_MEMBER).getStatus(), 
				party.getParty().get(THIRD_MEMBER).getStatus(), 
				party.getPlayer().getPicture(), 
				party.getParty().get(FIRST_MEMBER).getPicture(), 
				party.getParty().get(SECOND_MEMBER).getPicture(), 
				party.getParty().get(THIRD_MEMBER).getPicture(), 
				party.getPace(),
				party.getLevel(checkpoints));
		
		if (!game.listenersExist())
			createListeners();
		
		game.setRation(this.party.getRations());
		game.setPace(this.party.getPace());
	}
	
	/**
	 * Initializes all the checkpoints on the trail
	 */
	public void initCheckpoints()
	{
		//TODO: Create additional checkpoints
		//checkpoints.add(new Checkpoint("Independence", 0));
		
		
		//Image needs to be changed
		ImageIcon image = new ImageIcon("resources\\1_FieldsOfSorrow.jpg");
		ImageIcon image2 = new ImageIcon("resources\\1_GatesOfMinos.jpg");
		ImageIcon image3= new ImageIcon("resources\\2_DesertOfLust.jpg");
		ImageIcon image4 = new ImageIcon("resources\\2_RiverOfBlood.jpg");
		ImageIcon image5 = new ImageIcon("resources\\3_PillarOfCerberus.jpg");
		ImageIcon image6 = new ImageIcon("resources\\3_SwampsOfGluttony.jpg");
		ImageIcon image7 = new ImageIcon("resources\\4_RiverOfGreed.jpg");
		ImageIcon image8 = new ImageIcon("resources\\4_TowerOfPluto.jpg");
		ImageIcon image9 = new ImageIcon("resources\\5_RiverStyx.jpg");
		ImageIcon image10 = new ImageIcon("resources\\5_CityOfDis.jpg");
		ImageIcon image11 = new ImageIcon("resources\\6_RiverOfSouls.jpg");
		ImageIcon image12 = new ImageIcon("resources\\6_CanyonOfBurningTombs.jpg");
		ImageIcon image13 = new ImageIcon("resources\\7_RingsOfTheMinotaur.jpg");
		ImageIcon image14 = new ImageIcon("resources\\8_The10Borgia.jpg");
		ImageIcon image15 = new ImageIcon("resources\\9_Cocytus.jpg");
		
		//1st Circle
		createCheckpoint(new TownCheckpoint("Fields of Sorrow", 102, image, 1));
		createCheckpoint(new TownCheckpoint("Gates of Minos", 185, image2, 1));
		//2nd Circle
		createCheckpoint(new TownCheckpoint("Desert of Lust", 304, image3,2));
		createCheckpoint(new RiverCheckpoint("River of Blood", 554, image4, true, 10, 2));

		//3rd Circle
		createCheckpoint(new TownCheckpoint("Pillar of Cerberus", 640, image5,3));
		createCheckpoint(new RiverCheckpoint("Swamps of Gluttony", 830, image6, false, 2, 3));
		//4th Circle
		createCheckpoint(new RiverCheckpoint("River of Greed", 932, image7, false, 4, 4));
		createCheckpoint(new TownCheckpoint("Tower of Pluto", 1057, image8, 4));
		//5th Circle
		createCheckpoint(new RiverCheckpoint("River Styx", 1219, image9, true, 50, 5));
		createCheckpoint(new TownCheckpoint("City of Dis", 1276, image10, 5));
		//6th Circle
		createCheckpoint(new RiverCheckpoint("River of Souls", 1458, image11, false, 1, 6));
		createCheckpoint(new TownCheckpoint("Canyon of Burning Tombs", 1572, image12, 6));
		//7th Circle
		createCheckpoint(new TownCheckpoint("Rings of the Minotaur", 1734, image13, 7));
		//8th Circle
		createCheckpoint(new TownCheckpoint("The 10 Borgia", 1789, image14, 8));
		//9th Circle
		createCheckpoint(new TownCheckpoint("Cocytus", 1909, image15, 9));
		
		while(checkpoints.get(0).getLocation() < party.getTotalDistance()){
			checkpoints.remove(0);
		}
		
	}
	
	/**
	 * Create a checkpoint
	 */
	public void createCheckpoint(Checkpoint newCheck) {
		checkpoints.add(newCheck);
		permMap.add(newCheck);
	}
	
	/**
	 * Creats all the RandomEvents that can happen to the party on the trail
	 */
	public void initEvents(){
		//Test case for Random Events
		//Remove food isn't currently working
		thief = new ThiefEvent();
		illness = new IllnessEvent(party, mainView);
		wagonEvent = new WagonEvent();
		giving = new GivingEvent();
		recovered = new RecoverIllnessEvent(party);
		oxenDeath = new OxenDeathEvent(mainView);
		severeStorm = new SevereStromEvent();

		//Add more events to the list
		events.add(thief);
		events.add(illness);
		events.add(wagonEvent);
		events.add(giving);
		events.add(recovered);
		events.add(oxenDeath);
		events.add(severeStorm);
		
	}
	
	/**
	 * Creates the listeners needed for the components in the view
	 */
	@Override
	public void createListeners() {
		ActionListener moveListen = new MoveButtonListener();
		ActionListener mapListen = new MapButtonListener();
		ActionListener restListen = new RestButtonListener();
		ActionListener tradeListen = new TradeButtonListener();
		ActionListener infoListen = new PartyInfoButtonListener();
		ActionListener huntListen = new HuntButtonListener();
		ActionListener saveListen = new SaveButtonListener();
		ActionListener wagonListen = new WagonButtonListener();
		ActionListener partyListen = new PartyInfoButtonListener();
		game.setMoveButtonListener(moveListen);
		game.setRestButtonListener(restListen);
		game.setMapButtonListener(mapListen);
		game.setHuntButtonListener(huntListen);
		game.saveListener(saveListen);
		game.setWagonListener(wagonListen);
		game.setPartyInfoButtonListener(partyListen);

	}
	
	/**
	 * Returns a string representation of the GameViewController
	 * @return A string representation of the gameViewController
	 */
	@Override
	public String toString() {
		return ("This is a GameViewController");
	}
	
	/**
	 * Represents the listener for the move button
	 * @author David Chi
	 *
	 */
	private class MoveButtonListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			if (game.getMoveText().equals("Move")){
				game.setMoveText("Stop");
				game.disableButtons();
				timer.scheduleAtFixedRate(new MoveTask(), 1000, 1000);

			}
			else {
				timer.cancel();
				timer.purge();
				timer = new Timer();
				game.setMoveText("Move");
				game.enableButtons();
			}
		}
	}
	
	/**
	 * Handles the move step and calls the party class to handle its own data
	 */
	public void move(){
		party.setRations(game.getRation());
		party.setPace(game.getPace());
		int returnVal = party.step(game.getPace(), game.getRation(), checkpoints);
		
		if (returnVal == Party.OUT_OF_FOOD){
			timer.cancel();
			timer.purge();
			JOptionPane.showMessageDialog(mainView, "You do not have " +
					"enough food to continue on your journey. " + 
					"You are now resting at your current location.");
			game.enableButtons();
			game.setMoveText("Move");
			timer = new Timer();
		}
		else if (returnVal == Party.REACHED_DEST){
			game.setDistanceToCheckPoint(0);
			game.setDistanceTravelled(1909);
			timer.cancel();
			timer.purge();
			JOptionPane.showMessageDialog(mainView, "You have completed your journey!");
			game.enableButtons();
			game.setMoveText("Move");
		}
		else if (returnVal == Party.REACHED_CP){
			party.setDistanceLeft(0);
			game.setDistanceToCheckPoint(0);
			game.setDistanceTravelled(checkpoints.get(0).getLocation());
			party.setTotalDistance(checkpoints.get(0).getLocation());
			//game.setDistanceTravelled(party.getTotalDistance());
			timer.cancel();
			timer.purge();
			timer = new Timer();
//			checkpoints.remove(0);
			JOptionPane.showMessageDialog(mainView, "You have arrived at "+ checkpoints.get(0).getName() +"!");
			
			if(checkpoints.get(0) instanceof TownCheckpoint){
				TownViewController town = new TownViewController(party, mainView, this, checkpoints.get(0).getName());
				town.getTownView().setImage(checkpoints.get(0).getImage());
				((CardLayout) mainView.getContentPane().getLayout()).show(mainView.getContentPane(), "Town");
				mainView.setTitle(town.getName());
			}
			else{
				RiverViewController river = new RiverViewController(party, mainView, this, (RiverCheckpoint) checkpoints.get(0));
				river.getRiverView().setImage(checkpoints.get(0).getImage());
				((CardLayout) mainView.getContentPane().getLayout()).show(mainView.getContentPane(), "River");
				mainView.setTitle("River");
			}
			prevLocation = checkpoints.remove(0);
			party.setDistanceLeft(checkpoints.get(0).getLocation()-party.getTotalDistance());
			game.enableButtons();
			game.setMoveText("Move");
			
			
		}
		else {			
			Debug.println("" + party.getFood(), Debug.M_TEN_DEMO);
			for (int i = 0; i < events.size(); i ++){
				RandomEvent currEvent = events.get(i);
				if (currEvent instanceof SevereStromEvent && events.get(i).performEvent(party)){
					timer.cancel();
					timer.purge();
					timer = new Timer();
					JOptionPane.showMessageDialog(mainView, events.get(i).getMessage());
					day = day + 3;
					if (month == 2){
						if (day > 28){
							month++;
							day = day % 28;
							checkMonth = true;
						}
					}
					else if (checkMonth){
						if (day > 31 && month != 7 && month != 12){
							month++;
							day = day % 31;
							checkMonth = false;
						}
						else if (day > 31){
							month++;
							day = day % 31;
						}
					}
					else {
						if (day > 30){
							month++;
							day = day % 30;
						}
					}
					
					if (month > 12){
						year++;
						month = 1;
					}
					game.enableButtons();
					game.setMoveText("Move");
				}
				else if (events.get(i).performEvent(party)){
					timer.cancel();
					timer.purge();
					timer = new Timer();
					JOptionPane.showMessageDialog(mainView, events.get(i).getMessage());
					game.enableButtons();
					game.setMoveText("Move");
					//TODO: M11 DEMO CODE STARTS
					Debug.println(party.toString(), Debug.M_ELEVEN_DEMO);
					//TODO: M11 DEMO CODE ENDS
				}
			}
			Debug.println("" + party.getFood(), Debug.M_TEN_DEMO);
			game.setDistanceTravelled(party.getTotalDistance());
			party.setDistanceLeft(checkpoints.get(0).getLocation()-party.getTotalDistance());
			game.setDistanceToCheckPoint(party.getDistanceLeft());
			game.setRationsLeft(party.getFood());
			
			game.getDisplay().updateScreen(party.getPlayer().getStatus(), 
					party.getParty().get(0).getStatus(), 
					party.getParty().get(1).getStatus(), 
					party.getParty().get(2).getStatus(), 
					party.getPlayer().getPicture(), 
					party.getParty().get(0).getPicture(), 
					party.getParty().get(1).getPicture(), 
					party.getParty().get(2).getPicture(), 
					party.getPace(),
					party.getLevel(checkpoints));
		}
		
	}
	
	/**
	 * Private class representing the moveTask of the timer
	 * @author Vince Lugli
	 *
	 */
	private class MoveTask extends TimerTask{
		
		/**
		 * The methods that get called when the Timer runs.
		 */
		@Override
		public void run() {
			move();
			day++;
			if (month == 2){
				if (day > 28){
					month++;
					day = day % 28;
					checkMonth = true;
				}
			}
			else if (checkMonth){
				if (day > 31 && month != 7 && month != 12){
					month++;
					day = day % 31;
					checkMonth = false;
				}
				else if (day > 31){
					month++;
					day = day % 31;
				}
			}
			else {
				if (day > 30){
					month++;
					day = day % 30;
				}
			}
			
			if (month > 12){
				year++;
				month = 1;
			}
			
		}
		
	}
	
	private class MapButtonListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			((CardLayout) mainView.getContentPane().getLayout()).show(mainView.getContentPane(), "Map");
			mainView.setTitle("Map");
			
			String date = "";
			date = month + "/" + day + "/" + year;
			
			MapViewController mvc = new MapViewController(party, mainView, permMap, prevLocation, date);
			
		}
		
	}
	
	private class RestButtonListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			timer.cancel();
			timer.purge();
			timer = new Timer();
		}
		
	}
	
	private class TradeButtonListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			// TODO Auto-generated method stub
			
		}
		
	}
	
	private class PartyInfoButtonListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			//((CardLayout) mainView.getContentPane().getLayout()).show(mainView.getContentPane(), "Status");
			//mainView.setTitle("Party Info");
			
		}
		
	}
	
	private class HuntButtonListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			HuntingViewController hunting = new HuntingViewController(party, checkpoints, mainView);
			((CardLayout) mainView.getContentPane().getLayout()).show(mainView.getContentPane(), "Hunt");
			mainView.setTitle("Hunt");
			
		}
		
	}
	
	private class WagonButtonListener implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			WagonViewController hunting = new WagonViewController(party, mainView);
			((CardLayout) mainView.getContentPane().getLayout()).show(mainView.getContentPane(), "Wagon");
			mainView.setTitle("Wagon");
			
		}
		
	}
	
	private class SaveButtonListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			SaveFileHandler sfh = new SaveFileHandler();
			try{
				sfh.save(party);
			}
			catch(Exception ex){
				Debug.println("Save failed ", Debug.M_TEN_DEMO);
			}
		}
		
	}
	
	/*public static void main(String[] args)
	{Party party = new Party();
	JFrame frame = new JFrame();
	GameScreenDisplay dis = new GameScreenDisplay();
	party.add(new PartyMember("Bob"));
	party.add(new PartyMember("Bob"));
	party.add(new PartyMember("Bob"));
	party.addPlayer(new Player("Bob"));
		//GameViewController con = new GameViewController(party, frame);
		dis.updateScreen(party.getPlayer().getStatus(), party.getParty().get(0).getStatus(), 
				party.getParty().get(1).getStatus(), party.getParty().get(2).getStatus(), party.getPlayer().getPicture(), 
				party.getParty().get(0).getPicture(), party.getParty().get(1).getPicture(), party.getParty().get(2).getPicture(), 5);
		frame.add(dis);
		frame.setVisible(true);
		frame.pack();
		
	}*/

}


